namespace Agile.Genie.Descriptors
{
    using System;
    using Agile.Common.Reflections;

    /// <summary>
    /// Summary description for ClassDescriptor.
    /// </summary>
    public class ClassDescriptor
    {
        /// <summary>
        /// Constructor 
        /// </summary>
        /// <param name="className">Name of the class.</param>
        /// <param name="projectName">Name of the Project that the generated class is in.</param>
        /// <param name="subSystem">Name of the sub system the project is in.</param>
        /// <param name="inheritsFrom">Name of the class that this class inherits from</param>
        private ClassDescriptor(string className
                                , string projectName
                                , string subSystem
                                , string inheritsFrom)
        {
            _className = className;
            _projectName = projectName;
            _subSystem = subSystem;
            _inheritsFrom = inheritsFrom;
        }
        /// <summary>
        /// Constructor 
        /// </summary>
        /// <param name="agileType"></param>
        /// <param name="className">Name of the class.</param>
        /// <param name="projectName">Name of the Project that the generated class is in.</param>
        /// <param name="subSystem">Name of the sub system the project is in.</param>
        /// <param name="inheritsFrom">Name of the class that this class inherits from</param>
        private ClassDescriptor(AgileType agileType
            , string className
            , string projectName
            , string subSystem
            , string inheritsFrom) 
            : this (className, projectName, subSystem, inheritsFrom)
        {
            _agileType = agileType;
        }
        
        private AgileType _agileType;

        /// <summary>
        /// Instatiate a new Class descriptior.
        /// </summary>
        /// <param name="agileType"></param>
        /// <param name="className">Name of the class.</param>
        /// <param name="inheritsFrom">Name of the class that this class inherits from</param>
        /// <returns></returns>
        public static ClassDescriptor Instantiate(AgileType agileType
            , string className      
            , string inheritsFrom)
        {
            return new ClassDescriptor(agileType
                , className
                , agileType.ProjectName
                , agileType.SubSystemName
                , inheritsFrom);
        }

        /// <summary>
        /// Instatiate a new Class descriptior.
        /// </summary>
        /// <param name="className">Name of the class.</param>
        /// <param name="projectName">Name of the Project that the generated class is in.</param>
        /// <param name="subSystem">Name of the sub system the project is in.</param>
        /// <returns></returns>
        public static ClassDescriptor Instantiate(string className
                                             , string projectName
                                             , string subSystem)
        {
            return ClassDescriptor.Instantiate(className, projectName, subSystem, string.Empty);
        }

        /// <summary>
        /// Instatiate a new Class descriptior.
        /// </summary>
        /// <param name="className">Name of the class.</param>
        /// <param name="projectName">Name of the Project that the generated class is in.</param>
        /// <returns></returns>
        public static ClassDescriptor Instantiate(string className
                                             , string projectName)
        {
            return ClassDescriptor.Instantiate(className, projectName, string.Empty);
        }


        /// <summary>
        /// Instatiate a new Class descriptior.
        /// </summary>
        /// <param name="className">Name of the class.</param>
        /// <param name="projectName">Name of the Project that the generated class is in.</param>
        /// <param name="subSystem">Name of the sub system the project is in.</param>
        /// <param name="inheritsFrom">Name of the class that this class inherits from</param>
        /// <returns></returns>
        public static ClassDescriptor Instantiate(string className
                                             , string projectName
                                             , string subSystem
                                             , string inheritsFrom)
        {
            return new ClassDescriptor(className, projectName, subSystem, inheritsFrom);
        }



        #region Properties

        private string _className;
        private string _projectName;
        private string _subSystem;
        private string _inheritsFrom;

        /// <summary>
        /// Gets and sets the name of the class that this class inherits from
        /// </summary>
        public string InheritsFrom
        {
            get { return _inheritsFrom; }
            set { _inheritsFrom = value; }
        }

        /// <summary>
        /// Gets the name of the sub system the project is in.
        /// </summary>
        public string SubSystem
        {
            get { return _subSystem; }
        }


        /// <summary>
        /// Gets the Name of the class.
        /// </summary>
        public string Name
        {
            get
            {
                if ((_className == null) || (_className.Equals(string.Empty)))
                    throw new ApplicationException("Class Name has not been set.");
                return _className;
            }
        }

        /// <summary>
        /// Gets the name of the Project that the generated class is in.
        /// </summary>
        /// <example>DataLayer</example>
        public string ProjectName
        {
            get
            {
                if ((_projectName == null) || (_projectName.Equals(string.Empty)))
                    throw new ApplicationException("Project Name has not been set.");
                return _projectName;
            }
        }

        /// <summary>
        /// Gets the sub folders of the project (if there are any.)
        /// </summary>
        /// <example>'Agile.Common.Testing'
        /// would return 'Testing'</example>
        public string ProjectSubFolder
        {
            get
            {
                if (_agileType == null)
                    return string.Empty;
                return _agileType.ProjectSubFolder;
            }
        }

        #endregion

		/// <summary>
		/// Gets the layer suffix (if there is one).
		/// Note: this must be set after instantiation.
		/// </summary>
    	public string ClassNameSuffix
    	{
    		get { return _classNameSuffix; }
    		set { _classNameSuffix = value; }
    	}

    	private string _classNameSuffix = string.Empty;
		
		/// <summary>
		/// Gets the class name without it's suffix.
		/// </summary>
		/// <example>OrderDAL will return Order</example>
		public string NameWithoutSuffix
		{
			get
			{
				return Name.Substring(0, (Name.Length - ClassNameSuffix.Length));
			}
		}


    	private string _implementsInterface = string.Empty;
        /// <summary>
        /// Provides support for testing
        /// </summary>
        public class Testing
        {
            /// <summary>
            /// Class: TestClassName; Project: TestProjectName; SubSystem: TESTSubSystem
            /// </summary>
            /// <returns></returns>
            public static ClassDescriptor InstantiateTestClass()
            {
                return ClassDescriptor.Instantiate("TestClassName", "TestProjectName", "TESTSubSystem");
            }

            /// <summary>
            /// Class: TestClassName; Project: TestProjectName; SubSystem: ""
            /// </summary>
            /// <returns></returns>
            public static ClassDescriptor InstantiateTestClassWithoutSubSystem()
            {
                return ClassDescriptor.Instantiate("TestClassName", "TestProjectName");
            }

            /// <summary>
            /// Class: TestClassNameTests; Project: TestProjectName; SubSystem: TESTSubSystem
            /// </summary>
            /// <returns></returns>
            public static ClassDescriptor InstantiateTestTestsClass()
            {
                return ClassDescriptor.Instantiate("TestClassNameTests", "TestProjectName", "TESTSubSystem");
            }

            /// <summary>
            /// Class: TestClassNameCollection; Project: TestProjectName; SubSystem: TESTSubSystem
            /// </summary>
            /// <returns></returns>
            public static ClassDescriptor InstantiateTestCollectionClass()
            {
                return ClassDescriptor.Instantiate("TestClassNameCollection", "TestProjectName", "TESTSubSystem");
            }
        }

    }
}